5.08. Справочник по Smalltalk
Справочник по Smalltalk
1. Общие принципы языка
Smalltalk — это чисто объектно-ориентированный язык программирования, в котором всё является объектом. Каждое значение, каждая операция, каждый тип данных выражается через объекты и сообщения. Язык был разработан в 1970-х годах в исследовательском центре Xerox PARC как часть интегрированной среды разработки и обучения.
Smalltalk отличается минимальным синтаксисом, полной интерактивностью и мощной интроспекцией. Программы пишутся не в виде текстовых файлов, а в виде живых объектов, хранящихся в образе (image), который содержит всё состояние системы: код, данные, окружение, историю.
2. Основные концепции
2.1. Всё — объект
- Числа — объекты класса
Integer,Floatи подклассов. - Символы — объекты класса
Symbol. - Строки — объекты класса
String. - Булевы значения — объекты класса
TrueиFalse. - Классы — объекты класса
Class. - Методы — объекты класса
CompiledMethod. - Даже
nil— объект классаUndefinedObject.
2.2. Сообщения вместо вызовов
Взаимодействие между объектами происходит через отправку сообщений. Существует три типа сообщений:
2.2.1. Унарные сообщения
Сообщения без аргументов.
Пример:
3 factorial
Date today
'hello' reversed
2.2.2. Бинарные сообщения
Сообщения с одним аргументом, использующие специальные символы (+, -, =, >, //, @ и др.).
Пример:
5 + 3
a > b
point @ 10
2.2.3. Ключевые сообщения
Сообщения с именованными аргументами, где каждое ключевое слово заканчивается двоеточием.
Пример:
Array with: 1 with: 2 with: 3
Dictionary new at: 'key' put: 'value'
Point x: 10 y: 20
2.3. Приоритет сообщений
Порядок вычисления определяется строго:
- Унарные сообщения (слева направо)
- Бинарные сообщения (слева направо)
- Ключевые сообщения (слева направо)
Скобки () могут изменять порядок явно.
Пример:
3 + 4 factorial "означает 3 + (4 factorial) = 3 + 24 = 27"
(3 + 4) factorial "означает 7 factorial = 5040"
3. Синтаксис
3.1. Литералы
| Тип | Пример | Описание |
|---|---|---|
| Целые числа | 42 | Объект класса Integer |
| Вещественные | 3.14 | Объект класса Float |
| Строки | 'Hello' | Объект класса String |
| Символы | #hello | Объект класса Symbol |
| Массивы | #(1 2 3) | Литерал массива из литералов |
| Динамические массивы | {1. 2. 3} | Вычисляемый массив (в некоторых реализациях) |
| Блоки | `[ :x | x + 1 ]` |
| Хэш-литералы | #{'a' -> 1. 'b' -> 2} | Литерал словаря (в Pharo/Squeak) |
3.2. Переменные
3.2.1. Виды переменных
- Временные переменные: объявляются в методе через
| a b c | - Параметры блока: указываются после открывающей скобки блока, например
[ :x :y | x + y ] - Переменные экземпляра: принадлежат объекту, объявляются в классе
- Классовые переменные: общие для всех экземпляров класса
- Глобальные переменные: начинаются с заглавной буквы, например
Transcript,Smalltalk - Пул переменных: совместно используемые переменные, объявленные в отдельном пространстве
3.2.2. Объявление временных переменных
| a b result |
a := 10.
b := 20.
result := a + b.
^ result
3.3. Присваивание
Оператор присваивания — :=.
Пример:
x := 5.
name := 'Alice'.
Множественное присваивание возможно:
a := b := c := 0.
3.4. Возврат значения
Оператор ^ возвращает значение из метода или блока.
Если ^ не используется, метод возвращает self.
Пример:
double: x
^ x * 2
4. Блоки (замыкания)
Блоки — это объекты, представляющие исполняемый код. Они могут захватывать окружающий контекст.
4.1. Синтаксис
[ :arg1 :arg2 | выражение ]
Примеры:
[ 42 ] "блок без аргументов"
[ :x | x * x ] "блок с одним аргументом"
[ :a :b | a max: b ] "блок с двумя аргументами"
4.2. Выполнение блока
Блоки выполняются через унарные сообщения:
value— без аргументовvalue:— с одним аргументомvalue:value:— с двумя и т.д.
Пример:
increment := [ :x | x + 1 ].
result := increment value: 5. "результат — 6"
4.3. Использование в коллекциях
Блоки активно используются для итерации:
#(1 2 3 4) do: [ :each | Transcript show: each printString; cr ].
#(1 2 3 4) collect: [ :x | x * 2 ] "→ #(2 4 6 8)"
5. Классы и объекты
5.1. Создание класса
В среде Smalltalk классы создаются через браузер классов. Синтаксически определение класса выглядит так:
Object subclass: #MyClass
instanceVariableNames: 'name age'
classVariableNames: 'DefaultAge'
package: 'MyPackage'
5.2. Методы
Методы определяются в контексте класса. Синтаксис:
methodName
"комментарий"
| tempVar |
tempVar := self computeSomething.
^ tempVar
С параметрами:
setName: aString age: anInteger
name := aString.
age := anInteger
5.3. Конструкторы
Классовые методы часто служат фабриками:
MyClass class >> newWithName: aString
^ self new
setName: aString;
yourself
5.4. Наследование
Smalltalk поддерживает одиночное наследование. Все классы наследуются от Object, кроме ProtoObject.
Цепочка наследования:
ProtoObject → Object → Collection → SequenceableCollection → Array → ...
5.5. Метаклассы
Каждый класс — это объект, и у него есть собственный класс — метакласс. Метаклассы содержат методы, применимые к самому классу (например, new, initialize).
6. Коллекции
Smalltalk предоставляет богатую иерархию коллекций.
6.1. Основные типы
| Класс | Описание |
|---|---|
Array | Индексируемая последовательность фиксированной длины |
OrderedCollection | Динамический массив |
Set | Коллекция без дубликатов |
Dictionary | Хэш-таблица (ключ-значение) |
Bag | Коллекция с подсчётом вхождений |
Interval | Диапазон чисел (например, 1 to: 10) |
String | Последовательность символов |
ByteArray | Последовательность байтов |
6.2. Общие методы коллекций
do: aBlock— итерацияcollect: aBlock— преобразованиеselect: aBlock— фильтрация по условиюreject: aBlock— фильтрация с инверсиейanySatisfy: aBlock— проверка существованияallSatisfy: aBlock— проверка универсальностиsize— количество элементовisEmpty— проверка на пустотуincludes: anObject— проверка наличияat: index— доступ по индексуat: index put: value— запись по индексу
Пример:
numbers := #(1 2 3 4 5).
evens := numbers select: [ :x | x even ].
squares := numbers collect: [ :x | x * x ].
7. Исключения и обработка ошибок
Smalltalk использует механизм исключений на основе блоков.
7.1. Базовый синтаксис
[ riskyCode ] on: Error do: [ :ex | handleException ]
7.2. Типы исключений
Error— общая ошибкаMessageNotUnderstood— отправка неизвестного сообщенияSubscriptOutOfBounds— выход за границы массиваZeroDivide— деление на ноль
7.3. Возбуждение исключений
Error signal: 'Something went wrong'
7.4. Обеспечение и гарантированное выполнение
[ work ] ensure: [ cleanup ] "cleanup выполнится всегда"
8. Среда выполнения и инструменты
8.1. Образ (Image)
Вся система Smalltalk хранится в одном файле образа (.image). Он содержит:
- Все объекты
- Все классы и методы
- Все открытые окна и состояния
- Историю работы
Загрузка образа — мгновенный запуск всей среды.
8.2. Инструменты
- System Browser — просмотр и редактирование классов
- Workspace — интерактивная область для выполнения кода
- Transcript — системный лог
- Debugger — отладчик с возможностью изменения кода "на лету"
- Inspector — просмотр внутреннего состояния объекта
- Versions Browser — история изменений методов
8.3. Интроспекция
Smalltalk позволяет исследовать себя во время выполнения:
Object allSubclasses "все подклассы Object"
MyClass selectors "все методы класса"
method sourceCode "исходный код метода"
obj class "класс объекта"
obj respondsTo: #methodName "проверка поддержки сообщения"
9. Пакеты и модули
Smalltalk организует код в пакеты (Packages). Каждый класс принадлежит одному пакету. Пакеты:
- Группируют связанные классы
- Упрощают навигацию
- Используются при экспорте/импорте кода
- Поддерживают зависимости (в современных реализациях, например, Pharo)
10. Реализации Smalltalk
| Реализация | Особенности |
|---|---|
| Squeak | Ориентирована на образование, создана Alan Kay |
| Pharo | Современная, активно развиваемая, основанная на Squeak |
| VisualWorks | Коммерческая, мощная IDE, поддержка enterprise |
| GNU Smalltalk | Текстовая, похожа на скриптовые языки |
| VA Smalltalk | Для корпоративных решений, IBM-совместимость |
11. Стандартная библиотека (Kernel и Collections)
11.1. Класс Object — корень иерархии
Все объекты наследуют базовые методы от Object:
class— возвращает класс объектаisNil,notNil— проверка наnilifNil:,ifNotNil:— условное выполнениеyourself— возвращаетself(полезно для каскадирования)perform: aSymbol— динамическая отправка сообщенияperform:withArguments:— отправка с массивом аргументовshallowCopy,deepCopy— копированиеhash,=— сравнение и хэшированиеprintString,storeString— текстовое представление
Пример каскадирования:
Array new
add: 1;
add: 2;
yourself
11.2. Числовые классы
Integer— целые числа (подклассы:SmallInteger,LargePositiveInteger,LargeNegativeInteger)Float— числа с плавающей точкой (IEEE 754)Fraction— рациональные числа (3/4)Number— общий предок всех чисел
Методы:
+ - * / // \\— арифметикаabs,negated,reciprocaleven,oddto:,to:by:— создание интерваловfactorial,sqrt,sin,cos
Особенность: деление / всегда возвращает Float или Fraction, а // — целочисленное деление.
11.3. Строки и символы
String— изменяемая последовательность символовSymbol— неизменяемый, уникальный идентификатор
Методы строк:
size,isEmptyat:,at:put:copyFrom:to:includesSubsequence:,findString:asUppercase,asLowercaselines— разбивает на строкиwithCRs,withLFs— нормализация окончаний
Символы часто используются как ключи, селекторы методов, имена переменных.
11.4. Булевы значения
true— экземпляр классаTruefalse— экземпляр классаFalse
Методы:
ifTrue:,ifFalse:ifTrue:ifFalse:and:,or:,not
Пример:
(valid and: [ password size > 8 ]) ifTrue: [ self acceptLogin ]
Здесь and: принимает блок — ленивая оценка.
12. Графическая система: Morphic
Morphic — это каркас пользовательского интерфейса, используемый в Squeak и Pharo. Всё на экране — это морф (Morph), объект, умеющий рисовать себя и реагировать на события.
12.1. Основные морфы
| Морф | Назначение |
|---|---|
Morph | Базовый элемент UI |
RectangleMorph | Прямоугольник с цветом и границей |
StringMorph | Отображение текста |
ImageMorph | Отображение изображения |
TextMorph | Редактируемый многострочный текст |
PluggableButtonMorph | Кнопка с действием |
ScrollPane | Прокручиваемая область |
12.2. Создание и отображение
m := RectangleMorph new.
m color: Color red.
m extent: 100@100.
m openInHand. "показать в центре курсора"
12.3. События
Морфы реагируют на:
- клики (
mouseDown:,mouseUp:) - перемещение мыши (
mouseMove:) - клавиатуру (
keyStroke:) - перетаскивание (
startDrag:)
Можно переопределить методы или использовать on:send:to::
button on: #click send: #doSomething to: self
12.4. Компоновка
addMorph:— добавление дочернего морфаlayoutPolicy— стратегия размещения (например,TableLayout,LinearLayout)hResizing,vResizing— поведение при изменении размера
13. Сериализация и сохранение
13.1. storeString и readFrom:
Любой объект может быть преобразован в строку, пригодную для повторного чтения:
obj := #(1 2 3).
text := obj storeString. "→ '#(1 2 3)'"
restored := Compiler evaluate: text.
Работает для большинства литералов и простых структур.
13.2. Файловый ввод-вывод
file := 'data.txt' asFileReference writeStream.
file nextPutAll: 'Hello'.
file close.
content := 'data.txt' asFileReference contents.
13.3. Образ как форма сериализации
Поскольку весь мир Smalltalk — это образ, сохранение состояния достигается простым сохранением .image-файла. Это включает:
- Все объекты
- Все открытые окна
- Историю отладчика
- Текущие вычисления
Это мощный механизм, но не подходит для обмена с внешними системами.
13.4. JSON и XML
Современные реализации (Pharo) поддерживают:
NeoJSONReader,NeoJSONWriterXMLDOMParser
Пример:
json := NeoJSONObject new.
json at: 'name' put: 'Alice'.
jsonString := String streamContents: [ :s | (NeoJSONWriter on: s) write: json ].
14. Сетевые возможности
14.1. HTTP-клиент
Pharo предоставляет ZnClient (Zinc HTTP Components):
response := ZnClient new
url: 'https://api.example.com/data';
get.
data := response contents.
Поддержка:
- GET, POST, PUT, DELETE
- Заголовки
- JSON-тело
- Аутентификация
14.2. Сервер
Можно запустить встроенный HTTP-сервер:
server := ZnServer startOn: 8080.
server delegate: (ZnDefaultStaticServerDelegate directory: FileSystem workingDirectory).
Или создать REST API через маршрутизацию.
14.3. Сокеты
Низкоуровневый доступ через Socket:
socket := Socket newTCP.
socket connectTo: NetNameResolver loopbackAddress port: 8080.
socket sendData: 'PING'.
reply := socket receiveData.
15. Тестирование
Smalltalk включает встроенную систему модульного тестирования — SUnit (предтеча xUnit).
15.1. Написание теста
TestCase subclass: #MyClassTest
instanceVariableNames: ''
package: 'MyPackage-Tests'
MyClassTest >> testDouble
| result |
result := MyClass double: 5.
self assert: result equals: 10.
15.2. Утверждения
assert: aBooleanassert: actual equals: expectedassert: aCollection includes: anElementshould: [ code ] raise: Errorshouldnt: [ code ] raise: Error
15.3. Подготовка и завершение
setUp— выполняется перед каждым тестомtearDown— после каждого теста
Пример:
setUp
collection := OrderedCollection new.
testAdd
collection add: 42.
self assert: collection size equals: 1.
16. Внешние вызовы (FFI)
Smalltalk может вызывать нативные библиотеки через Foreign Function Interface.
Пример (Pharo + UFFI):
LibC class >> ffiLibrary
^ #('libc.so.6')
LibC class >> strlen: aString
<cdecl: long 'strlen' (char*) module: #('libc.so.6')>
^ self externalCallFailed
Использование:
len := LibC strlen: 'hello' asByteArray.
Требует осторожности: ошибки могут упасть всю систему.
17. Практические примеры
17.1. Калькулятор выражений
evaluate: expressionString
^ Compiler evaluate: expressionString
⚠️ Только в доверенной среде!
Compiler evaluate:исполняет любой код.
17.2. Реализация стека
Stack := OrderedCollection.
push: item
self addLast: item.
pop
^ self removeLast.
isEmpty
^ self isEmpty.
17.3. Observer-паттерн
subject addDependent: observer.
subject changed.
"observer получит #update: от subject"
Smalltalk включает эту модель «из коробки» через Model и Dependents.
18. Настройки и параметры среды
18.1. Глобальные настройки
Доступны через Smalltalk preferences:
cmdKeysInText— использовать Cmd-комбинации в текстеscrollBarsWithoutMenuButton— стиль прокруткиannotationPane— показ аннотаций в браузере
18.2. Цвета и шрифты
StandardFonts defaultFont: (LogicalFont familyName: 'Source Code Pro' pointSize: 12).
Color blue muchDarker.
18.3. Логирование
Transcript show: 'Debug info'; cr.
Transcript clear.
Transcript — глобальный объект вывода, видимый в отдельном окне.
19. Производительность и оптимизация
- Избегайте частого создания больших коллекций в циклах
- Используйте
becomeForward:осторожно — меняет идентичность объектов #=и#hashдолжны быть согласованы для использования вSet/Dictionary- Блоки без захвата контекста компилируются эффективнее
SmallIntegerоперации — самые быстрые (встроены в VM)
20. Экосистема и сообщество
- Pharo — активное сообщество, ежегодные конференции (Pharo Days)
- GitHub — тысячи пакетов на github.com/pharo-project
- Catalog — менеджер пакетов в Pharo (
World menu → Tools → Catalog) - Pillar — система документирования (аналог Markdown + LaTeX)
- Glamour — фреймворк для создания инструментов анализа кода